package cc.eddic.pratice.programmingparadigms.exam.impl;


import cc.eddic.pratice.programmingparadigms.exam.Model.AnswerModel;
import cc.eddic.pratice.programmingparadigms.exam.QuestionBankService;
import cc.eddic.pratice.programmingparadigms.exam.QuestionType;
import cc.eddic.pratice.programmingparadigms.exam.domain.Category;
import cc.eddic.pratice.programmingparadigms.exam.domain.Option;
import cc.eddic.pratice.programmingparadigms.exam.domain.Question;
import cc.eddic.pratice.programmingparadigms.exam.domain.SubCategory;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.function.Predicate;

@Slf4j
public class QuestionBankServiceZyzImpl extends QuestionBankServiceImpl implements QuestionBankService {


    @Override
    public List<Question> importQuestions(String questionTextFile) {

        String fileContent = getQuestionFileContent();
        List<Question> questionList = new ArrayList<>();

        String[] lines = fileContent.split("\\R");
        int numLines = lines.length;

        for (int i = 0; i < numLines; i++) {

            if (lines[i].isEmpty()) {
                continue;
            }

            int no = Integer.parseInt(lines[i].substring(0, lines[i].indexOf('、')));
            String description = lines[i].substring(lines[i].indexOf('、') + 1);
            QuestionType qt = QuestionType.SINGLE_CHOICE;

            Question q = new Question(no, description, qt);

            i++;
            q.add(new Option(lines[i].substring(lines[i].indexOf('、') + 1), 'A', false));
            i++;
            q.add(new Option(lines[i].substring(lines[i].indexOf('、') + 1), 'C', false));
            i++;
            q.add(new Option(lines[i].substring(lines[i].indexOf('、') + 1), 'D', false));
            i++;
            q.add(new Option(lines[i].substring(lines[i].indexOf('、') + 1), 'B', false));


            questionList.add(q);
        }

        return questionList;
    }

    @Override
    public List<Question> importCorrectAnswers(String correctAnswerTextFile) {
        List<Question> questionList = importQuestions("");
        Map<Integer, Character> answerMap = readCorrectAnswers2("");

        for (Question q : questionList) {
            if (!answerMap.containsKey(q.getNo())) {
                continue;
            }

            char choice = answerMap.get(q.getNo());
            Optional<Option> optionalOption = q.getOptions().stream().filter(new Predicate<Option>() {
                @Override
                public boolean test(Option option) {
                    return option.getChoice() == choice;
                }
            }).findFirst();

            Option option2 = q.getOptions().stream()
                    .filter(option -> option.getChoice() == choice)
                    .findFirst()
                    .orElseThrow(() -> new IllegalArgumentException("question " + q.getNo() + " has no choice " + choice));


            if (optionalOption.isPresent()) {
                optionalOption.get().changeToCorrectAnswer();
            } else {
                log.error("question {} has no choice {}", q.getNo(), choice);
            }
        }
        return questionList;
    }

    @Override
    public List<AnswerModel> readCorrectAnswers(String correctAnswerTextFile) {
        return null;
    }


    @Override
    public List<Question> importCategories(String categoryExcelFile) {
        try {
            Workbook workbook = new XSSFWorkbook(new FileInputStream(categoryExcelFile)); // Read Excel file
            Sheet categorySheet = workbook.getSheetAt(0); // First sheet of Excel file
            Row categoryRow = categorySheet.getRow(0); // First row(row of categories)
            Row rowSubCategory = categorySheet.getRow(1); // Second row(row of subcategories)
            List<CellRangeAddress> listMergedCellRangeAddresses = categorySheet.getMergedRegions(); // List of merged cells


            List<Question> listQuestions = importCorrectAnswers(""); // Get Question List
            Map<String, Category> mapCategories = new HashMap<>();
            Map<String, SubCategory> mapSubCategories = new HashMap<>();

            int numQuestions = listQuestions.size(); // Number of Questions
            Iterator<Row> rowIterator = categorySheet.rowIterator(); // Create a Row Iterator
            rowIterator.next(); // Iterate over Category row
            rowIterator.next(); // Iterate over SubCategory row
            for (int i = 0; i < numQuestions; i++) {

                Row row = rowIterator.next();
                int questionNo = (int) row.getCell(0).getNumericCellValue(); // Question No, whose value stored in the first cell

                Iterator<Cell> cellIterator = row.cellIterator();
                cellIterator.next(); // Iterate over Question No
                while (cellIterator.hasNext()) {
                    Cell cell = cellIterator.next();
                    if ((int) cell.getNumericCellValue() == 1) {
                        int indexColumnSubCategory = cell.getColumnIndex();
                        String nameSubCategory = rowSubCategory.getCell(indexColumnSubCategory).
                                getRichStringCellValue().getString(); // Subcategory name

                        CellRangeAddress cellRangeAddressCategory = listMergedCellRangeAddresses.stream().filter(
                                x -> indexColumnSubCategory >= x.getFirstColumn() && indexColumnSubCategory <= x.getLastColumn()
                        ).findFirst().orElse(null);

                        int indexRowCategory = cellRangeAddressCategory == null ? 0 : cellRangeAddressCategory.getFirstRow();
                        int indexColumnCategory = cellRangeAddressCategory == null ? indexColumnSubCategory : cellRangeAddressCategory.getFirstColumn();
                        String nameCategory = categorySheet.getRow(indexRowCategory).getCell(indexColumnCategory).
                                getRichStringCellValue().getString();

                        log.debug("SubCategory: " + nameSubCategory + "  Category: " + nameCategory + "\n");

                        if (  mapSubCategories.containsKey(nameSubCategory)) {
                            listQuestions.stream().filter(q -> q.getNo() == questionNo).findFirst().
                                    orElse(null).setSubCategory(mapSubCategories.get(nameSubCategory));
                        }
                        else {
                            mapSubCategories.put(nameSubCategory, new SubCategory(nameSubCategory));

                            if (! mapCategories.containsKey(nameCategory)) {
                                mapCategories.put( nameCategory , new Category(nameCategory) );
                            }

                            Category category = mapCategories.get(nameCategory);
                            SubCategory subCategory = mapSubCategories.get(nameSubCategory);
                            category.add(subCategory);
                            subCategory.setCategory(category);

                        }

                        break;
                    }
                }


            }

            return listQuestions;

        } catch (FileNotFoundException e) {
            log.error("importCategories FileInputStream FileNotFoundException\n");
        } catch (IOException e) {
            log.error("importCategories XSSFWorkbook IOException\n");
        }

        return null;

    }


    @Override
    public Map<Integer, Character> readCorrectAnswers2(String correctAnswerTextFile) {
        Map<Integer, Character> result = new HashMap<>();
        String[] lines = getAnswerFileContent().split("\n");
        for (int i = 0; i < lines.length; i += 2) {
            String[] nos = lines[i].split("\t");
            String[] choices = lines[i + 1].split("\t");
            for (int j = 0; j < nos.length; j++) {
                String no = nos[j];
                String choice = choices[j];
                result.put(Integer.parseInt(no), choice.charAt(0));
            }
        }
        return result;
    }


}
